# JoinTablePolymorphism.java

    package org.codefilarete.stalactite.engine.configurer.model;

    import java.util.Map;
    import java.util.Set;
    import java.util.stream.Collectors;

    import org.codefilarete.stalactite.sql.ddl.structure.Table;
    import org.codefilarete.tool.collection.KeepOrderMap;
    import org.codefilarete.tool.collection.KeepOrderSet;

    /**
     * Each subclass has its own dedicated table that joins to the parent
     * table via a FK on the subclass table pointing to the parent PK.
     *
     * @param <C>  parent entity type
     * @param <I>  identifier type
     * @param <T>  parent table type
     */
    public class JoinTablePolymorphism<C, I, T extends Table<T>> implements EntityPolymorphism<C, I> {

        /** Sub-entities with their own tables, keyed by subclass type */
        private final Map<Class<? extends C>, JoinedSubEntity<? extends C, ?>> subEntities = new KeepOrderMap<>();

    	public <D extends C, SUBTABLE extends Table<SUBTABLE>> void addSubEntity(
    			Class<D> subType,
    			Mapping<D, SUBTABLE> subEntity, DirectRelationJoin<T, SUBTABLE, I> join) {
    		subEntities.put(subType, new JoinedSubEntity<>(subEntity, join));
    	}

    	@Override
    	public Set<Mapping<? extends C, ?>> getSubEntities() {
    		return subEntities.values().stream().map(JoinedSubEntity::getSubEntity).collect(Collectors.toCollection(KeepOrderSet::new));
    	}

    	/**
    	 * A sub-entity in join-table polymorphism. It holds its own table and the FK join back to the parent.
    	 *
    	 * @param <D> the subclass entity type
    	 * @param <SUBTABLE> the subclass-specific table type
    	 */
    	public class JoinedSubEntity<D extends C, SUBTABLE extends Table<SUBTABLE>> {

    		private final Mapping<D, SUBTABLE> subEntity;

    		/** Join: subTable.FK → parentTable.PK */
    		private final DirectRelationJoin<T, SUBTABLE, I> join;

    		public JoinedSubEntity(Mapping<D, SUBTABLE> subEntity, DirectRelationJoin<T, SUBTABLE, I> join) {
    			this.subEntity = subEntity;
    			this.join = join;
    		}

    		public Mapping<D, SUBTABLE> getSubEntity() {
    			return subEntity;
    		}

    		public DirectRelationJoin<T, SUBTABLE, I> getJoin() {
    			return join;
    		}
    	}
    }